﻿//
// Copyright(C) MixModes Inc. 2011
// 

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MixModes.Phone.Synergy.Extensions
{
    /// <summary>
    /// FrameworkElement extension methods
    /// </summary>
    public static class FrameworkElementExtensions
    {        
        /// <summary>
        /// This method ensures that the Widths and Heights are initialized.  
        /// Sizing to content produces Width and Height values of Double.NaN.  
        /// Because this Adorner explicitly resizes, the Width and Height
        /// need to be set first.  It also sets the maximum size of the adorned element.
        /// </summary>
        /// <param name="elementToResize">Element to resize</param>
        public static void EnforceSize(this FrameworkElement elementToResize)
        {
            if (elementToResize.Width.Equals(Double.NaN))
            {
                elementToResize.Width = elementToResize.DesiredSize.Width;
            }

            if (elementToResize.Height.Equals(Double.NaN))
            {
                elementToResize.Height = elementToResize.DesiredSize.Height;
            }
        }        

        /// <summary>
        /// Gets the first visual parent of specified type or null if no parent of that type is found
        /// </summary>
        /// <typeparam name="T">Type of parent to search</typeparam>
        /// <param name="element">The element</param>
        /// <returns>First visual parent of specified type or null if no parent of that type is found</returns>
        public static T GetVisualParent<T>(this FrameworkElement element) where T : FrameworkElement
        {
            DependencyObject parent = element;

            do
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            while ((parent != null) && (!(parent is T)));

            return parent as T;
        }

        /// <summary>
        /// Gets the named child.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent">The parent.</param>
        /// <param name="controlName">Name of the control. If null then first control of type <typeparamref name="T"/> is returned</param>
        /// <returns>Named element of type <typeparamref name="T"/> if there is one; otherwise if controlName is null first control of type <typeparamref name="T"/>; otherwise null</returns>
        public static T GetNamedChild<T>(this FrameworkElement parent, string controlName) where T : Control
        {
            T foundChild = null;

            int childCount = VisualTreeHelper.GetChildrenCount(parent);

            for (int i = 0; i < childCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;

                T typedChild = child as T;

                if (typedChild == null)
                {
                    foundChild = GetNamedChild<T>(child, controlName);

                    if (foundChild != null)
                    {
                        break;
                    }
                }
                else if (!string.IsNullOrEmpty(controlName))
                {
                    if (typedChild.Name == controlName)
                    {
                        foundChild = typedChild;
                        break;
                    }
                }
                else
                {
                    foundChild = typedChild;
                    break;
                }
            }

            return foundChild;
        }

        /// <summary>
        /// Gets the first child of specified type
        /// </summary>
        /// <typeparam name="T">Type of child</typeparam>
        /// <param name="parent">The parent.</param>
        /// <returns>Returns first child of specified type if there is one; null otherwise</returns>
        public static T GetFirstChild<T>(this FrameworkElement parent) where T : Control
        {
            return GetNamedChild<T>(parent, null);
        }

        /// <summary>
        /// Gets all children.
        /// </summary>
        /// <param name="root">The root.</param>
        /// <returns>All decendent children of root</returns>
        public static IEnumerable<DependencyObject> GetAllChildren(DependencyObject root)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(root, i);
                yield return child;

                foreach (var subChild in GetAllChildren(child))
                {
                    yield return subChild;
                }
            }
        }        
    }
}
